package com.xxx.rabbitmq.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Slf4j
@RestController
public class TestController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * ①简单发送
     * 没有通过交换机exchange路由，而是直接发送到指定队列。
     * 一般用于一个生产者、一个消费者
     * <a href="http://localhost:8080/simpleSend?msg=simpleMsg1">...</a>
     */
    @RequestMapping("/simpleSend")
    public String simpleSend(String msg) {
        String queueName = "simple.queue";
        rabbitTemplate.convertAndSend(queueName, msg);
        log.info("simpleSend消息发送完成："+msg);
        return msg;
    }

    /**
     * ②直接发送
     * 通过交换机exchange+路由key进行路由发送，消息会被匹配的多个消费者进行消费（消费者彼此没有关联）
     * <a href="http://localhost:8080/directSend?msg=directMsg1&routingKey=routingK">...</a>
     */
    @RequestMapping("/directSend")
    public String directSend(String routingKey, String msg) {
        String exchangeName = "direct.exchange";
        rabbitTemplate.convertAndSend(exchangeName, routingKey, msg);
        log.info("directSend消息发送完成："+msg);
        return msg;
    }

    /**
     * ③fanout发送
     * 扇出发送：消息会被绑定的多个消费者消费，跟路由键无关，类似广播模式或订阅模式，将消息发送到所有绑定到该交换机的队列
     * <a href="http://localhost:8080/fanoutSend?msg=fanoutMsg1">...</a>
     */
    @RequestMapping("/fanoutSend")
    public String fanoutSend(String msg) {
        String exchangeName = "fanout.exchange";
        rabbitTemplate.convertAndSend(exchangeName, "", msg);
        log.info("fanoutSend消息发送完成："+msg);
        return msg;
    }

    /**
     * ④topic发送
     * 模糊绑定：配置灵活，支持路由key的模糊匹配，这样方便配置，而不用逐个绑定每一个交换机和队列
     * 一般用于需要匹配多个路由key的复杂场景，例如：不同级别的日志（debug、info、error）分别路由到不同的消费者
     * 每一个“.”代表路由key的一组
     * #：匹配0个或多个单词
     * *：匹配1个单词
     */
    // 能被routingKey为【china.#】的topic队列接收到
    // http://localhost:8080/topicSend?msg=topicMsg1
    @RequestMapping("/topicSend")
    public String topicSend(String msg) {
        String exchangeName = "topic.exchange";
        rabbitTemplate.convertAndSend(exchangeName, "china.#", msg);
        log.info("topic消息发送完成："+msg);
        return msg;
    }
    // 能被routingKey为【#.news】的topic队列接收到
    // http://localhost:8080/topicSend2?msg=topicMsg1
    @RequestMapping("/topicSend2")
    public String topicSend2(String msg) {
        String exchangeName = "topic.exchange";
        rabbitTemplate.convertAndSend(exchangeName, "#.news", msg);
        log.info("topic消息发送完成："+msg);
        return msg;
    }
    // 能同时被routingKey为【red】和【#.news】的topic队列接收到
    // http://localhost:8080/topicSend3?msg=topicMsg3
    @RequestMapping("/topicSend3")
    public String topicSend3(String msg) {
        String exchangeName = "topic.exchange";
        rabbitTemplate.convertAndSend(exchangeName, "red", msg);
        log.info("topic消息发送完成："+msg);
        return msg;
    }

    /**
     * ⑤过期消息
     * 指定消息过期时间，如果到了过期时间仍未被消费，则消息会被删除.
     * <a href="http://localhost:8080/ttlSend?msg=ttlMsg1">...</a>
     */
    @RequestMapping("/ttlSend")
    public String ttlSend(String msg) {
        Message message = MessageBuilder
                .withBody(msg.getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .setExpiration("15000")  // 过期时间：15s（15s内会被消费，否则自动被删除）
                .build();
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(
                "ttl.exchange",
                "ttl",
                message,
                correlationData
        );
        log.info("ttlMsgSend过期消息发送完成："+msg);
        return msg;
    }

    /**
     * ⑥延时队列
     * 利用死信交换机实现延时消息
     * 消息先被暂存在普通队列normal.queue中，如果延时时间到了，就会被投递到延时队列delay.queue中，消费者会从延时队列里接收到消息进行消费；
     * 注意：1.如果没有被消费也不会被删除。2.在延时时间到达之前，也不会被消费（因为还没有被投递到延时队列里）.3.跟过期消息的区别时，过期消息到期后如果到期仍未被消费就会会被删除。
     * <a href="http://localhost:8080/delaySend?msg=delayMsg1">...</a>
     */
    @RequestMapping("/delaySend")
    public String delaySend(String msg) {
//        // 延时消息发送方式1：在发送方法里带上 CorrelationData
//        Message message = MessageBuilder
//                .withBody(msg.getBytes(StandardCharsets.UTF_8))
//                .setMessageId(UUID.randomUUID().toString())  // 设置消息ID
//                .setHeader("x-delay", 10000)   // x-delay-message插件实现延时队列，过期时间：10s
//                .build();
//        CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
//        rabbitTemplate.convertAndSend("delay.exchange", "delay", message, cd);

        // 延时消息发生方式2：在message的properties中设置延时时间
        rabbitTemplate.convertAndSend("delay.exchange", "delay", msg, message ->{
            message.getMessageProperties().setMessageId(UUID.randomUUID().toString());  // 设置消息ID
            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);  //消息持久化
            message.getMessageProperties().setDelay(10000);   // 延时时间：10s
            return message;
        });

        log.info("delaySend延时消息发送完成："+msg);
        return msg;
    }

    /**
     * ⑦复杂消息体
     * 需要先声明MessageConverter，例如在RabbitMqConfig声明Bean：jsonMessageConverter
     * <a href="http://localhost:8080/objectSend">...</a>
     */
    @RequestMapping("/objectSend")
    public Map<String, Object> objectSend() {
        Map<String, Object> msg = new HashMap<>();
        msg.put("name", "Jack");
        msg.put("age", 21);
        String exchangeName = "direct.exchange";
        rabbitTemplate.convertAndSend(exchangeName, "blue", msg);
        log.info("objectSend消息发送完成："+msg);
        return msg;
    }

//    /**
//     * ⑧事务消息
//     * <a href="http://localhost:8080/txSend">...</a>
//     */
//    @Transactional("rabbitTransactionManager")
//    @RequestMapping("/txSend")
//    public String txSend(String msg) {
//        try {
//            // 发送消息
//            rabbitTemplate.convertAndSend("direct.exchange", "yellow", msg);
//            System.out.println("Sent: " + msg);
//
//            // 模拟业务逻辑
//            if (msg.contains("error")) {
//                throw new RuntimeException("模拟业务逻辑失败");
//            }
//
//            // 提交事务
//            System.out.println("事务提交成功");
//        } catch (Exception e) {
//            // 回滚事务
//            System.out.println("事务回滚，原因: " + e.getMessage());
//            throw e;
//        }
//        return msg;
//    }

}
